﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jarvis.Server.Domain;
using Jarvis.Server.Location;
using Jarvis.Server.Repositories;
using Ninject.Extensions.Logging;

namespace Jarvis.Server.Statistics
{
    public class StatisticsCollector : IStatisticsCollector
    {
        private readonly ILocationProvider _locationProvider;
        private readonly ILocationStatsRepository _locationStats;
        private readonly ILogger _logger;
        
        private Domain.Location _lastLocation = null;

        public StatisticsCollector(ILocationProvider locationProvider, ILocationStatsRepository locationStats,ILoggerFactory loggerFactory)
        {
            _locationProvider = locationProvider;
            _locationStats = locationStats;
            _logger = loggerFactory.GetCurrentClassLogger();
        }

        
        private void InsertOrUpdateLocationStats(DateTime now, Domain.Location loc, LocationStatsEntry.EntryKind entryKind)
        {

            LocationStats persistedStat;
            
            lock (_locationStats)
            {


                persistedStat = (from l in _locationStats.All()
                                     where l.Location.Id == loc.Id
                                     select l).FirstOrDefault();

            }

            if (persistedStat != null)
            {
                persistedStat.Entries.Add(new LocationStatsEntry { Date = now, Kind = entryKind });


                lock (_locationStats)
                {
                    _locationStats.Update(persistedStat);
                }

            }
            else
            {
                persistedStat = new LocationStats
                {
                    Entries = new List<LocationStatsEntry>
                                                      {
                                                          new LocationStatsEntry
                                                              {
                                                                  Date = now,
                                                                  Kind = entryKind
                                                              }
                                                      },
                    Location = loc
                };
                lock (_locationStats)
                {
                    _locationStats.Add(persistedStat);
                }
            }
        }

        #region Implementation of IStatisticsCollector

        public IList<LocationStats> GetAllStats()
        {
            lock (_locationStats)
            {
                return _locationStats.All().ToList();
            }
        }

        public LocationStats StatsForLocation(Domain.Location location)
        {
            lock (_locationStats)
            {
                return (from l in _locationStats.All()
                        where l.Location.Id == location.Id
                        select l).First();
            }
        }

        public bool IsCollecting { get; private set; }

        public void StartCollecting()
        {
            IsCollecting = true;

            _locationProvider.CurrentLocationChanged += CurrentLocationChanged;
        }

        public void StopCollecting()
        {
            _locationProvider.CurrentLocationChanged -= CurrentLocationChanged;
            IsCollecting = false;
        }

        #endregion

        void CurrentLocationChanged(object sender, LocationEventArgs e)
        {
            _logger.Trace("Collecting stats for location {0}",e.Location.Name);
            if (_lastLocation == null)
            {
                _lastLocation = e.Location;
                if (_lastLocation != null)
                {
                    InsertOrUpdateLocationStats(DateTime.Now, _lastLocation, LocationStatsEntry.EntryKind.Enter);
                }
            }
            else
            {
                var location = e.Location;
                if (location != null)
                {
                    if (_lastLocation.Id != location.Id)
                    {
                        InsertOrUpdateLocationStats(DateTime.Now, _lastLocation, LocationStatsEntry.EntryKind.Exit);
                        InsertOrUpdateLocationStats(DateTime.Now, location, LocationStatsEntry.EntryKind.Enter);
                    }
                    _lastLocation = location;
                }
            }
        }
        
    }

    
}
